package com.ruoyi.driver.utils;

import cn.hutool.crypto.digest.DigestUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.TypeReference;
import com.ruoyi.driver.enums.FaceActionEnum;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import java.io.IOException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.ZoneId;
import java.util.Base64;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

/**
 * @author lipengze
 * @version 1.0
 * @description: 数脉api工具类
 * @date 2024/10/23 9:01
 */
@Component
@Slf4j
public class ShuMaiUtils {
    @Value("${shumai.appid}")
    private String appid;
    @Value("${shumai.appsecret}")
    private String secret;
    @Value("${shumai.faceUrl}")
    private String faceUrl;
    @Value("${shumai.faceImageUrl}")
    private String faceUImageUrl;
    @Value("${shumai.faceIdCardUrl}")
    private String faceIdCardUrl;
    @Resource
    private OSSFileUtil ossFileUtil;
    /**
     * 文件上传到 OSS
     * @param file
     * @return
     * @throws IOException
     */
    public String uploadFile(MultipartFile file) throws IOException {
        log.info("开始上传文件......");
        String filePath = ossFileUtil.uploadFile(file);
        log.info("文件上传成功--->>>>{}", filePath);
        return filePath;
    }
    /**
     * 文件字节流上传到 OSS
     * @param bytes
     * @return
     * @throws IOException
     */
    public String uploadFile(byte[] bytes) throws IOException {
        log.info("开始上传文件......");
        String filePath = ossFileUtil.uploadFile(bytes);
        log.info("文件上传成功--->>>>{}", filePath);
        return filePath;
    }

    /**
     * 文件转换为 Base64 字符串
     * @param file 文件
     * @return base64
     * @throws IOException
     */
    public String convertToBase64(MultipartFile file) throws IOException {
        byte[] fileBytes = file.getBytes();
        return Base64.getEncoder().encodeToString(fileBytes);
    }

    /**
     * 生成 MD5 签名
     * @param timestamp 时间戳
     * @return 签名
     */
    public String generateSignature(String timestamp) {
        String sign = DigestUtil.md5Hex(appid + "&" + timestamp + "&" + secret);// 生成md5签名
        log.info("MD5签名生成成功--->>>>{}", sign);
        return sign;
    }

    /**
     * 发送 POST 请求
     * @param url 请求路径
     * @param timestamp 时间戳
     * @param sign 签名
     * @param imageBase64 64位图片
     * @return
     */
    public String sendPostRequest(String url, String timestamp, String sign,String imageBase64) throws IOException {
        Map<String, Object> map = new HashMap<>();
        map.put("appid", appid);
        map.put("timestamp", timestamp);
        map.put("sign", sign);
        map.put("image", imageBase64);

        String result = HttpClientUtils.sendPostNoJson(url, map);
        log.info("请求结果--->>>>{}", result);
        return result;
    }
    /**
     * 发送 POST活体检测 请求
     * @param requestUrl 请求路径
     * @param timestamp 时间戳
     * @param sign 签名
     * @param url 视频路径
     * @return
     */
    public String sendPost(String requestUrl, String timestamp, String sign,String url,String motions) throws IOException {
        Map<String, Object> map = new HashMap<>();
        map.put("appid", appid);
        map.put("timestamp", timestamp);
        map.put("sign", sign);
        map.put("url", url);
        map.put("motions", motions);

        String result = HttpClientUtils.sendPostNoJson(requestUrl, map);
        log.info("请求结果--->>>>{}", result);
        return result;
    }
    /**
     * 发送 POST活体检测 请求
     * @param requestUrl 请求路径
     * @param timestamp 时间戳
     * @param sign 签名
     * @param url 视频路径
     * @param idcard 身份证号
     * @param name 姓名
     * @return
     */
    public String sendPost(String requestUrl, String timestamp, String sign,String url,String idcard,String name) throws IOException {
        Map<String, Object> map = new HashMap<>();
        map.put("appid", appid);
        map.put("timestamp", timestamp);
        map.put("sign", sign);
        map.put("url", url);
        map.put("idcard", idcard);
        map.put("name", name);

        String result = HttpClientUtils.sendPostNoJson(requestUrl, map);
        log.info("请求结果--->>>>{}", result);
        return result;
    }
    /**
     * 发送 POST 请求并获取结果
     * @param apiUrl api地址
     * @param file  文件
     * @return
     * @throws IOException
     */
    public Map<String, Object> processApiRequest(String apiUrl, MultipartFile file) throws IOException {
        // 获取 Base64 字符串
        String imageBase64 = convertToBase64(file);
        // 获取当前时间戳
        String timestamp = System.currentTimeMillis() + "";
        // 生成 MD5 签名
        String sign = generateSignature(timestamp);
        // 发送 POST 请求并返回结果
        String jsonResult = sendPostRequest(apiUrl, timestamp, sign, imageBase64);
        return handleApiResponse(jsonResult);
    }

    /**
     * 发送 POST 人脸请求并获取结果
     * @param apiUrl api地址
     * @param filePath 视频地址
     * @return
     * @throws IOException
     */
    public Map<String, Object> faceApiRequest(String apiUrl, String filePath) throws IOException {
        // 获取当前时间戳
        String timestamp = System.currentTimeMillis() + "";
        // 生成 MD5 签名
        String sign = generateSignature(timestamp);
        //必填参数 识别动作类型
        String motions = FaceActionEnum.MOUTH.getActionName();
        // 发送 POST 请求并返回结果
        String jsonResult = sendPost(apiUrl, timestamp, sign, filePath,motions);
        return handleApiResponse(jsonResult);
    }
    /**
     * 发送 POST 人证对比 请求并获取结果
     * @param apiUrl api地址
     * @param filePath 视频地址
     * @return
     * @throws IOException
     */
    public Map<String, Object> faceIdCradApiRequest(String apiUrl, String filePath,Map<String,Object> map) throws IOException {
        // 获取当前时间戳
        String timestamp = System.currentTimeMillis() + "";
        // 生成 MD5 签名
        String sign = generateSignature(timestamp);
        //获取身份证号
        String number = (String) map.get("number");
        //获取姓名
        String name = (String) map.get("name");
        // 发送 POST 请求并返回结果
        String jsonResult = sendPost(apiUrl, timestamp, sign, filePath,number,name);
        return handleApiResponse(jsonResult);
    }

    /**
     * 解析 JSON 结果
     * @param jsonResult json响应结果
     * @return
     */
    public Map<String, Object> handleApiResponse(String jsonResult) {
        // 将 JSON 字符串解析为 Map
        Map<String, Object> responseMap = JSON.parseObject(jsonResult, new TypeReference<Map<String, Object>>() {});
        log.info("响应结果--->>>>" + responseMap);
        return responseMap;
    }

    /**
     * 判断结果是否成功
     * @param resultMap  响应结果
     * @return
     */
    public boolean isRequestSuccessful(Map<String, Object> resultMap) {
        return Boolean.TRUE.equals(resultMap.get("success")) && Integer.valueOf(200).equals(resultMap.get("code"));
    }

    /**
     * 统一的异常处理
     * @param resultMap 响应结果
     */
    public void handleFailure(Map<String, Object> resultMap) {
        if (!isRequestSuccessful(resultMap)) {
            throw new RuntimeException(resultMap.get("msg").toString());
        }
    }
    /**
     * 校验驾驶证日期是否在有效期范围内
     * @param startDateStr 开始日期字符串，格式为 yyyyMMdd
     * @param endDateStr 结束日期字符串，格式为 yyyyMMdd
     * @throws RuntimeException 如果当前日期不在有效期范围内，抛出异常
     */
    public void validateDateRange(String startDateStr, String endDateStr) {
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyyMMdd");
        try {
            // 将字符串转换为日期
            Date startDate = simpleDateFormat.parse(startDateStr);
            Date endDate = simpleDateFormat.parse(endDateStr);
            // 获取当前日期
            LocalDate currentDate = LocalDate.now();

            // 将 startDate 和 endDate 转换为 LocalDate
            LocalDate startLocalDate = startDate.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
            LocalDate endLocalDate = endDate.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();

            // 判断当前日期是否在有效期范围之外
            if (currentDate.isBefore(startLocalDate) || currentDate.isAfter(endLocalDate)) {
                throw new RuntimeException("驾驶证已过期");
            }
        } catch (ParseException e) {
            throw new IllegalArgumentException("日期转换过程中出现了异常",e);
        }
    }

    /**
     * 人脸识别工具接口
     * @param file
     * @return
     * @throws IOException
     */
    public Map<String,Object> recognizeFace (MultipartFile file,Map<String,Object> map) throws IOException{
        String ossPath = uploadFile(file);

        Map<String, Object> apiResponse = faceApiRequest(faceUrl, ossPath);
        handleFailure(apiResponse);
        //获取第一层  data对象
        Map<String,Object> data = (Map<String, Object>) apiResponse.get("data");
        //特征图像id
        String featureImageId = (String) data.get("feature_image_id");
        //检测结果
        boolean passed = (boolean) data.get("passed");
        byte[] bytes = HttpClientUtils.sendGetByte(faceUImageUrl + featureImageId);
        String ossFacePath = uploadFile(bytes);//活体特征照片
        if (Boolean.FALSE.equals(passed)) {
            throw new RuntimeException("人脸识别失败");
        }
        Map<String, Object> faceIdResponse = faceIdCradApiRequest(faceIdCardUrl, ossFacePath, map);
        handleFailure(faceIdResponse);//已经做了是否成功的判断
        return faceIdResponse;
    }
}
